#include "file_func.h"

#if defined(unix) || defined(__unix) || defined(__unix__)
#define POSIX_MODE
#elif
#define WIN32_MODE
#endif


#include <fstream>
#include <cstring>
#include <iostream>

#ifdef POSIX_MODE

const char* CONCAT = "/";

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

#endif

#ifdef WIN32_MODE

const char* CONCAT = "\";

#include <windows.h>
#include <winbase.h>

#endif

bool doesFileExist(const char* filename)
{
  std::ifstream fileTest(filename);
  fileTest.close();
  if (fileTest.fail())
  {
    fileTest.clear(std::ios::failbit);
    return false;
  }
  return true;
}

char** getDirectoryListing(const char* directory_name, int& itemCount)
{

  /* Posix code */
#ifdef POSIX_MODE

  itemCount = 0;

  DIR* d = opendir(directory_name);
  struct dirent* dirp;
  while ((dirp = readdir(d)) != 0)
  {
    if (std::strcmp(dirp->d_name, ".") != 0 && std::strcmp(dirp->d_name, "..") != 0)
    {
      itemCount++;
    }
  }
  closedir(d);

  d = opendir(directory_name);
  char** paths = new char*[itemCount];
  for (int i = 0; i < itemCount; i++)
  {
    dirp = readdir(d);
    if (std::strcmp(dirp->d_name, ".") != 0 && std::strcmp(dirp->d_name, "..") != 0)
    {
      paths[i] = dirCombine(directory_name, dirp->d_name);
    }
    else
    {
      i--;
    }
  }
  closedir(d);
  return paths;
#endif

  return 0;
}

bool isDirectory(const char* filename)
{
#ifdef POSIX_MODE
  struct stat _stat;
  lstat(filename, &_stat);
  return _stat.st_mode&S_IFDIR;
#endif
}
bool isRegular(const char* filename)
{
#ifdef POSIX_MODE
  struct stat _stat;
  lstat(filename, &_stat);
  return _stat.st_mode&S_IFREG;
#endif
}
int getModifiedDate(const char* filename)
{
  struct stat _stat;
  lstat(filename, &_stat);
  return _stat.st_mtime;
}
char* dirCombine(const char* a, const char* b)
{
  char* tmp = strCombine(a, CONCAT);
  char* final = strCombine(tmp, b);
  delete[] tmp;
  return final;
}

char* strCombine(const char* a, const char* b)
{
  char* strResult = new char[std::strlen(a) + std::strlen(b) + 1];
  std::strcpy(strResult, a);
  std::strcat(strResult, b);
  return strResult;
}

bool isBinary(const char* filename)
{
  const unsigned long MAX_FILE_SIZE = 1024*30;
  std::ifstream fReader(filename, std::ios::binary);
  unsigned char buffer[1024];
  if (!fReader)
  {
    return 1;
  }
  else
  {
    fReader.seekg(0, std::ios::end);
    unsigned long length = fReader.tellg();
    fReader.seekg(0, std::ios::beg);
    
    if (length > MAX_FILE_SIZE)
    {
      fReader.close();
      return 1;
    }

    if (length > 1023)
    {
      length = 1023;
    }
    fReader.read((char *)buffer, length);
    fReader.close();

    buffer[length + 1] = '\0';

    bool rChar = 0;
    bool spaceHit = 0;
    int nNonText = 0;
    for (int i = 0; buffer[i] != '\0' && i < 1024; i++)
    {
      if (buffer[i]=='\n' || buffer[i]=='\t')
      {
        buffer[i] = ' ';
      }
      
      if (buffer[i + 1] == '\0' && (i + 1) < length)
      {
        return 1;
      }

      rChar = 1;
      if (buffer[i] < 32 || buffer[i] > 127)
      {
        nNonText++;
      }
      if (buffer[i]==' ' || buffer[i]=='\n')
      {
        spaceHit = 1;
      }
      if (spaceHit==0 && i > 15)
      {
        return 1;
      }
    }
    if (length > 0)
    {
      if (nNonText*100/length > 5)
      {
        return 1;
      }
    }
    return 1 - rChar;
  }
}
